#Importation des librairies nécessaires au projet
#!pip install geopandas
import json
from datetime import timedelta
from urllib.request import urlopen
import numpy as np
import pandas as pd
#import geopandas as gpd
import requests
#!pip install folium
# basic visualization package
import matplotlib.pyplot as plt
# advanced ploting
import seaborn as sns
# interactive visualization
import plotly.express as px
import plotly.graph_objs as go
import plotly.io as pio
# import plotly.figure_factory as ff
from plotly.subplots import make_subplots
#Chargement total des données
#On force le type de certaines colonnes qui créaient des bugs
column_dtypes = {
"Code departement": "object",
"No Volume": "object",
"1er lot": "object",
"Surface Carrez du 1er lot": "object",
"2eme lot": "object",
"Surface Carrez du 2eme lot": "object",
"3eme lot": "object",
"Surface Carrez du 3eme lot": "object",
"4eme lot": "object",
"Surface Carrez du 4eme lot": "object",
"5eme lot": "object",
"Surface Carrez du 5eme lot": "object",
"Nature culture speciale": "object",
}
#On prépare un dictionnaire reliant les départements à leur nom de région
REGIONS = {
'Auvergne-Rhône-Alpes': ['01', '03', '07', '15', '26', '38', '42', '43', '63', '69', '73', '74'],
'Bourgogne-Franche-Comté': ['21', '25', '39', '58', '70', '71', '89', '90'],
'Bretagne': ['35', '22', '56', '29'],
'Centre-Val de Loire': ['18', '28', '36', '37', '41', '45'],
'Corse': ['2A', '2B'],
'Grand Est': ['08', '10', '51', '52', '54', '55', '57', '67', '68', '88'],
'Guadeloupe': ['971'],
'Guyane': ['973'],
'Hauts-de-France': ['02', '59', '60', '62', '80'],
'Île-de-France': ['75', '77', '78', '91', '92', '93', '94', '95'],
'La Réunion': ['974'],
'Martinique': ['972'],
'Normandie': ['14', '27', '50', '61', '76'],
'Nouvelle-Aquitaine': ['16', '17', '19', '23', '24', '33', '40', '47', '64', '79', '86', '87'],
'Occitanie': ['09', '11', '12', '30', '31', '32', '34', '46', '48', '65', '66', '81', '82'],
'Pays de la Loire': ['44', '49', '53', '72', '85'],
'Provence-Alpes-Côte d\'Azur': ['04', '05', '06', '13', '83', '84'],
}
#Et un dictionnaire avec le nom de département en fonction du code de département,ils seront utiles
#pour des affichages plus propres sur
departements = {
'01': 'Ain',
'02': 'Aisne',
'03': 'Allier',
'04': 'Alpes-de-Haute-Provence',
'05': 'Hautes-Alpes',
'06': 'Alpes-Maritimes',
'07': 'Ardèche',
'08': 'Ardennes',
'09': 'Ariège',
'10': 'Aube',
'11': 'Aude',
'12': 'Aveyron',
'13': 'Bouches-du-Rhône',
'14': 'Calvados',
'15': 'Cantal',
'16': 'Charente',
'17': 'Charente-Maritime',
'18': 'Cher',
'19': 'Corrèze',
'21': 'Côte-d\'Or',
'22': 'Côtes-d\'Armor',
'23': 'Creuse',
'24': 'Dordogne',
'25': 'Doubs',
'26': 'Drôme',
'27': 'Eure',
'28': 'Eure-et-Loir',
'29': 'Finistère',
'2A': 'Corse-du-Sud',
'2B': 'Haute-Corse',
'30': 'Gard',
'31': 'Haute-Garonne',
'32': 'Gers',
'33': 'Gironde',
'34': 'Hérault',
'35': 'Ille-et-Vilaine',
'36': 'Indre',
'37': 'Indre-et-Loire',
'38': 'Isère',
'39': 'Jura',
'40': 'Landes',
'41': 'Loir-et-Cher',
'42': 'Loire',
'43': 'Haute-Loire',
'44': 'Loire-Atlantique',
'45': 'Loiret',
'46': 'Lot',
'47': 'Lot-et-Garonne',
'48': 'Lozère',
'49': 'Maine-et-Loire',
'50': 'Manche',
'51': 'Marne',
'52': 'Haute-Marne',
'53': 'Mayenne',
'54': 'Meurthe-et-Moselle',
'55': 'Meuse',
'56': 'Morbihan',
'57': 'Moselle',
'58': 'Nièvre',
'59': 'Nord',
'60': 'Oise',
'61': 'Orne',
'62': 'Pas-de-Calais',
'63': 'Puy-de-Dôme',
'64': 'Pyrénées-Atlantiques',
'65': 'Hautes-Pyrénées',
'66': 'Pyrénées-Orientales',
'67': 'Bas-Rhin',
'68': 'Haut-Rhin',
'69': 'Rhône',
'70': 'Haute-Saône',
'71': 'Saône-et-Loire',
'72': 'Sarthe',
'73': 'Savoie',
'74': 'Haute-Savoie',
'75': 'Paris',
'76': 'Seine-Maritime',
'77': 'Seine-et-Marne',
'78': 'Yvelines',
'79': 'Deux-Sèvres',
'80': 'Somme',
'81': 'Tarn',
'82': 'Tarn-et-Garonne',
'83': 'Var',
'84': 'Vaucluse',
'85': 'Vendée',
'86': 'Vienne',
'87': 'Haute-Vienne',
'88': 'Vosges',
'89': 'Yonne',
'90': 'Territoire de Belfort',
'91': 'Essonne',
'92': 'Hauts-de-Seine',
'93': 'Seine-Saint-Denis',
'94': 'Val-de-Marne',
'95': 'Val-d\'Oise',
}
#On crée la fonction qui associera la région en fonction du département
def get_region(department):
for region, departments in REGIONS.items():
if department in departments:
return region
return None
#Premier chargement de nos données,ici on charge le fichier entier sans être tries.
full_data=pd.read_csv(r"valeursfoncieres-2022.txt",sep='|',dtype=column_dtypes)
#on supprime les données si la colonne entiere est nulle
full_data=full_data.dropna(how='all',axis = 1)
#On remplace les donnes de type object par des float si possible
full_data["Valeur fonciere"] = full_data["Valeur fonciere"].str.replace(',', '.').astype(float)
#On affecte une valeur de date à la date mutation qui avait un type object
full_data["Date mutation"] = pd.to_datetime(full_data["Date mutation"], format='%d/%m/%Y')
#On ne conserve que les colonnes qui nous intéresse
data=full_data[['Date mutation' ,'Nature mutation','Valeur fonciere','Code postal','Code departement',
'Surface reelle bati','Surface terrain','Type local','Type de voie','Code voie','Voie',
'No voie','Nombre de lots','Code commune','Commune']]
#On supprime lorsque la valeur de la valeur fonciere ou de la surface reelle
#n'existe pas ou si elle est inférieur à 1 (données non intérressantes)
data=data.dropna(subset=['Valeur fonciere','Surface reelle bati'])
data=data[(data['Valeur fonciere']>1) & (data['Surface reelle bati']>1)]
#On s'occupe mainteant du problème des lots
#Pour cela on regroupe les data si la date de mutation, la valeur fonciere, et le code departement sont les mêmes
#On calcule ensuite une colonne surface totale contenant la somme des surfaces réelles bati de tout les biens à cette adresse
#et on rajoute donc un colonne Prix m² en divisant la valeur fonciere par la surface totale
data['adresse'] = data['Date mutation'].astype(str) + '-' + data['Code departement'].astype(str) + '-' + data['Valeur fonciere'].astype(str)
surface_par_lot = data.groupby('adresse')['Surface reelle bati'].sum().reset_index()
surface_par_lot.rename(columns={'Surface reelle bati': 'Surface_totale'}, inplace=True)
#On rajoute la colonne surface_totale à nos data de base
data= data.merge(surface_par_lot, on='adresse', how='left')
#On ajoute une colonne Prix m²
data['Prix m²'] = data['Valeur fonciere'] / data['Surface_totale']
#On peut observer qu'il reste des valeurs abberantes ( Des prix au m² < a environ 0.00048 ou des prix au m² a
#plusieurs centaines de millieurs d'euros)
#On va donc supprimer les valeurs, nous avons décide de garder les prix au m²<500 000 et les prix au m²>10
data=data[(data['Prix m²']<1000000) & (data['Prix m²']>10)]
#on ajoute une colonne qui prend la valeur fonciere par lot et non la valeur fonciere total du lot pour chaque lot
nombre_par_lot=data.groupby('adresse').size().reset_index(name='Nombre par lot')
data=data.merge(nombre_par_lot, on='adresse', how='left')
data['Valeur fonciere par lot']=data['Valeur fonciere']/data['Nombre par lot']
#On ajoute maintenant les noms des régions et des départements
data['Region'] = data['Code departement'].apply(get_region)
data['Nom departement']=data['Code departement'].map(departements)
#On ajoute une colonne mois qui permettra de faire des graphes en fonction du mois
data['Mois'] = data['Date mutation'].dt.month
#data.sort_values(by="Prix m²").tail(50)
#Création d'une fonction qui permet de lire et de faire le nettoyage de nos données (pour les 4 autres années)
def lecture(path):
#On récupere le fichier en entier
full_data2021=pd.read_csv(path,sep='|',dtype=column_dtypes)
#On supprime les colonnes avec toutes les valeurs nulles
full_data2021=full_data2021.dropna(how='all',axis = 1)
#On change le type des données importantes
full_data2021["Valeur fonciere"] = full_data2021["Valeur fonciere"].str.replace(',', '.').astype(float)
full_data2021["Date mutation"] = pd.to_datetime(full_data2021["Date mutation"], format='%d/%m/%Y')
#On décide de ne
data2021=full_data2021[['Date mutation' ,'Nature mutation','Valeur fonciere',
'Code postal','Code departement','Surface reelle bati','Surface terrain','Type local','Code voie','Nombre de lots','Code commune','Commune']]
#On supprime lorsque la valeur n'existe pas ou si elle est inférieur à 1 (données non intérressante)
data2021=data2021.dropna(subset=['Valeur fonciere','Surface reelle bati'])
data2021=data2021[(data2021['Valeur fonciere']>1) & (data2021['Surface reelle bati']>1)]
#On s'occupe mainteant du problème des lots
#Pour cela on regroupe les data si leur date de mutation leur valeur fonciere, et leur code departement sont les mêmes
#On calcule ensuite la somme de tout les biens à cette adresse
#et on rajoute donc un colonne Prix m² en divisant la valeur fonciere par la surface totale
data2021['adresse'] = data2021['Date mutation'].astype(str) + '-' + data2021['Code departement'].astype(str) + '-' + data2021['Valeur fonciere'].astype(str)
surface_par_lot2021 = data2021.groupby('adresse')['Surface reelle bati'].sum().reset_index()
surface_par_lot2021.rename(columns={'Surface reelle bati': 'Surface_totale'}, inplace=True)
data2021= data2021.merge(surface_par_lot2021, on='adresse', how='left')
data2021['Prix m²'] = data2021['Valeur fonciere'] / data2021['Surface_totale']
#On peut observer qu'il reste des valeurs abberantes ( Des prix au m² < a environ 0.00048 ou des prix au m² a
#plusieurs centaines de millieurs d'euros)
#On va donc supprimer les valeurs, nous avons décide de garder les prix au m²<500 000 et les prix au m²>10
data2021=data2021[(data2021['Prix m²']<1000000) & (data2021['Prix m²']>10)]
#on ajoute une colonne qui prend la valeur fonciere par lot et non la valeur fonciere total du lot pour chaque lot
nombre_par_lot2021=data2021.groupby('adresse').size().reset_index(name='Nombre par lot')
data2021=data2021.merge(nombre_par_lot2021, on='adresse', how='left')
data2021['Valeur fonciere par lot']=data2021['Valeur fonciere']/data2021['Nombre par lot']
return data2021
data2021=lecture(r"valeursfoncieres-2021.txt")
data2020=lecture(r"valeursfoncieres-2020.txt")
data2019=lecture(r"valeursfoncieres-2019.txt")
data_2018=lecture(r"valeursfoncieres-2018.txt")
C:\Users\paull\AppData\Local\Temp\ipykernel_24316\1426354948.py:4: DtypeWarning: Columns (14) have mixed types. Specify dtype option on import or set low_memory=False. full_data2021=pd.read_csv(path,sep='|',dtype=column_dtypes)
#On essaye de faire quelques graphiques pour explorer et voir les données de notre dataset,
#Ce graphique permet de voir la répartition de notre dataset
repartition=data.groupby(by='Type local')['Date mutation'].count().reset_index()
repartition = repartition.rename(columns={'Date mutation': 'count type local'})
data2=data.copy()
data2=data2.merge(repartition, left_on='Type local',right_on='Type local')
fig=px.pie(data2,values='count type local',names='Type local',title='Répartition de la quantité en fonction du type local')
fig.show()
#On observe que l'on a une majorité de maison, 40% d'appartement, et seulement 1,7% de local industriel
#Pour certains graphique suivants, nous allons préférés nous concentrés seulement sur des graphiques
#avec les maisons et les appartements